import tkinter as tk
from tkinter import messagebox
import time
import threading

# 全局变量
points = []  # 二维数组
play = True
w = 10
h = 10
light_x = w // 2
light_y = h // 2
glass = 3  # 光在玻璃中反应时间
air = 2  # 光在空气中的反应时间
glass_rgb = '#646464'  # 玻璃默认色
air_rgb = '#000000'  # 空气默认色
RGB = [4, 5, 6]
glass_w = 0
glass_h = 10

# 初始化像素点
def init_points():
    global points, glass_w
    for yi in range(h):
        if yi < glass_h:
            glass_w += 1
        else:
            glass_w = 0
        points.append([])
        for xi in range(w):
            point = {}
            light = 0  # 初始光子数为0
            if xi > glass_w:
                point['name'] = 'air'
                point['timer'] = air  # 反应时间
            else:
                point['name'] = 'glass'
                point['timer'] = glass
                # 随机玻璃
                rand = int((3 * time.time()) % 3)  # 简单模拟随机
                point['color'] = RGB[rand]
            key = f'data_{yi}_{xi}'
            point['key'] = key
            point['light'] = light
            points[yi].append(point)

# 绘制表格
def draw_table():
    for yi in range(h):
        for xi in range(w):
            name = points[yi][xi]['name']
            if name == 'air':
                color = air_rgb
            else:
                color = glass_rgb
            label = tk.Label(root, width=3, height=1, bg=color)
            label.grid(row=yi + 1, column=xi)  # +1 是为了给按钮等控件留出空间

# 开始照射
def light():
    global play
    play = True
    step = 0
    for yi in range(h):
        for xi in range(w):
            name = points[yi][xi]['name']
            t = points[yi][xi]['timer']
            if name == 'air':
                threading.Thread(target=lambda y=yi, x=xi: f_air(y, x)).start()
            else:
                threading.Thread(target=lambda y=yi, x=xi: f_glass(y, x)).start()
            # 初始化光源
            if xi == light_x and yi == light_y:
                try:
                    num = int(photons_entry.get())
                    points[yi][xi]['light'] = num
                    show_light(yi, xi, name, num)
                except ValueError:
                    messagebox.showerror("错误", "请输入有效的光子数")
            step += 1

# 暂停独立计算
def stop():
    global play
    play = not play

# 空气介质独立计算
def f_air(yi, xi):
    while play:
        self_light = points[yi][xi]['light']
        base = f_base(yi, xi, self_light)
        arr_sotr = base[0]
        sum_val = base[1]
        max_val = base[2]
        show = 0
        for j in range(len(arr_sotr)):
            if arr_sotr[j] != 0:
                # 向下取整数：当前差值的与总差值的比重
                num = int(((self_light - arr_sotr[j][1]) / sum_val) * (self_light - max_val))
                # 只要大于1就更新数据
                if num > 0:
                    y, x = arr_sotr[j][0]
                    points[y][x]['light'] += num
                show += num
        if show > 0:
            # 只要分配大于就发光一次（脉冲）
            show_light(yi, xi, points[yi][xi]['name'], show)
            # 减去已经分配的量
            points[yi][xi]['light'] -= show
            labels[yi][xi].config(text=points[yi][xi]['light'])
        time.sleep(0.1)  # 简单控制速度

# 玻璃介质独立计算
def f_glass(yi, xi):
    while play:
        self_light = points[yi][xi]['light']
        color = points[yi][xi]['color']  # 玻璃的私有方法
        base = f_base(yi, xi, self_light)
        arr_sotr = base[0]
        sum_val = base[1]
        max_val = base[2]
        show = 0
        for j in range(len(arr_sotr)):
            if arr_sotr[j] != 0:
                # 向下取整数：当前差值的与总差值的比重，并返回RGB的整倍数
                len_val = int((self_light - max_val) / color)
                num = int(((self_light - arr_sotr[j][1]) / sum_val) * len_val * color)
                # 以上便是两种介质的主要不同之处
                if num > 0:
                    y, x = arr_sotr[j][0]
                    points[y][x]['light'] += num
                show += num
        if show > 0:
            show_light(yi, xi, points[yi][xi]['name'], show, color)
            points[yi][xi]['light'] -= show
            labels[yi][xi].config(text=points[yi][xi]['light'])
        time.sleep(0.1)  # 简单控制速度

# 公共则：返回符合条件的邻近像素点
def f_base(yi, xi, self_light):
    arr = []
    # 上（前），虚空默认为0
    up = (0, 0)
    if yi - 1 > -1:
        up = (yi - 1, xi)
    arr.append(up)
    # 下（后），虚空默认为0
    down = (0, 0)
    if yi + 1 < h:
        down = (yi + 1, xi)
    arr.append(down)
    # 左，虚空默认为0
    left = (0, 0)
    if xi - 1 > -1:
        left = (yi, xi - 1)
    arr.append(left)
    # 右，虚空默认为0
    right = (0, 0)
    if xi + 1 < w:
        right = (yi, xi + 1)
    arr.append(right)
    arr_sotr = []  # 排序后的像素值
    sum_val = 0
    max_val = 0  # 仅次于自己的像素值
    for i in range(len(arr)):
        y, x = arr[i]
        if y == 0 and x == 0:
            n = 0
        else:
            n = points[y][x]['light']
        if n < self_light:
            if n > max_val:
                max_val = n
            sum_val += (self_light - n)  # 总势能差
            arr_sotr.append([(y, x), n])
    return [arr_sotr, sum_val, max_val]

# 发光（脉冲）
def show_light(yi, xi, name, num, color=0):
    css = '#FFFFFF'  # 初始化为白光
    if color == RGB[0]:
        css = '#FF0000'  # 红光
    if color == RGB[1]:
        css = '#00FF00'  # 绿光
    if color == RGB[2]:
        css = '#0000FF'  # 蓝光
    labels[yi][xi].config(bg=css)
    # 恢复原有颜色
    root.after(100, lambda y=yi, x=xi, n=name: reset_color(y, x, n))

# 恢复颜色
def reset_color(yi, xi, name):
    if name == 'air':
        labels[yi][xi].config(bg=air_rgb)
    else:
        labels[yi][xi].config(bg=glass_rgb)

# 创建主窗口
root = tk.Tk()
root.title("光锥实验（独立计算）")

# 创建控件
stop_button = tk.Button(root, text="暂停", command=stop)
stop_button.grid(row=0, column=0)

photons_entry = tk.Entry(root, width=5)
photons_entry.insert(0, "999")
photons_entry.grid(row=0, column=1)

start_button = tk.Button(root, text="开始照射", command=light)
start_button.grid(row=0, column=2)

# 初始化像素点
init_points()

# 绘制表格
labels = []
for yi in range(h):
    row_labels = []
    for xi in range(w):
        name = points[yi][xi]['name']
        if name == 'air':
            color = air_rgb
        else:
            color = glass_rgb
        label = tk.Label(root, width=3, height=1, bg=color)
        label.grid(row=yi + 1, column=xi)
        row_labels.append(label)
    labels.append(row_labels)

# 运行主循环
root.mainloop()